package main

import (
	"fmt"
	"reflect"
)

//反射的最佳实践
//使用反射遍历结构体的字段 调用结构体的方法 获取结构体标签的值
func main() {
	test(1)
	test(Empty{})
	test(Student{
		Name: "路飞",
		Age:  20,
	})
}

//myTag是自定义tag
type Student struct {
	Name string `json:"stuName" myTag:"姓名"`
	Age  uint8  `json:"age" myTag:"年龄"`
}

func (stu Student) A() {
	fmt.Println("A方法被调用了")
}

func (stu Student) B() string {
	return stu.Name
}

func (stu Student) C(num1 int32, num2 int32) int32 {
	return num1 + num2
}

type Empty struct {
}

func test(obj interface{}) {
	//1.获取kind
	rType := reflect.TypeOf(obj)
	rKind := rType.Kind()
	if rKind != reflect.Struct {
		fmt.Println("必须是结构体")
		return
	}
	//获取Value
	rVal := reflect.ValueOf(obj)
	//获取结构体具备几个字段
	fieldCount := rType.NumField() //也可以用rVal.NumField()

	if fieldCount == 0 {
		fmt.Println("当前结构体无任何字段")
		return
	}
	fmt.Println("当前结构体具备", fieldCount, "个字段")

	for i := 0; i < fieldCount; i++ {
		fVal := rVal.Field(i)
		fieldName := rType.Field(i).Name
		//获取结构体字段的tag,注意这里需要用Type

		jsontag := rType.Field(i).Tag.Get("json")
		if jsontag != "" {
			fmt.Printf("字段名：%v  tag值:%v 值:%v \n", fieldName, jsontag, fVal)
		}

		//获取自定义tag

		myTag := rType.Field(i).Tag.Get("myTag")
		if myTag != "" {
			fmt.Printf("字段名：%v  tag值:%v 值:%v \n", fieldName, myTag, fVal)
		}
	}

	//获取结构体的方法
	methodCount := rType.NumMethod()
	if methodCount == 0 {
		fmt.Println("结构体无方法")
		return
	}

	//方法的排序默认是按照ASCII 升序排序
	rVal.Method(0).Call(nil) //这里调用的是A方法

	vals := rVal.Method(1).Call(nil)
	for index, v := range vals {
		fmt.Printf("index:%v v:%v\n", index, v)
	}

	//方法3需要传入参数
	var params []reflect.Value
	params = append(params, reflect.ValueOf(int32(1)))
	params = append(params, reflect.ValueOf(int32(2)))
	result := rVal.Method(2).Call(params)
	fmt.Println(result[0])
}
